#!/bin/bash

curr_path=$(pwd)

OVPN_CONF="${curr_path}/etc/client.ovpn"
STUNNEL_CONF="${curr_path}/etc/stunnel.conf"


config=0
modpin=0
stop=0

#显示脚本支持可选项
show_usage() {
	if [ -n "$1" ]; then
		echo "错误: $1" >&2
	fi
	
cat 1>&2 <<EOF

使用: bash $0 [选项]

选项:
  --config                      修改VPN客户端配置文件
  --modpin                      修改usbkey pin口令
  --stop                      	停止VPN服务
  -h, --help                    显示此帮助消息并退出
  
EOF
	exit 1
}

#参数解析
parse_args() {
	while [ "$#" -gt 0 ]; do
		echo "参数：$1"
		case $1 in
			--config)
				config=1
				shift
				;;
			--modpin)
				modpin=1
				shift
				;;
			--stop)
				stop=1
				shift
				;;
			-h|--help)
				show_usage
				;;
			*)
				show_usage "未知参数: $1"
				;;
		esac
	done
}

check_ip() {
	IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
	printf '%s' "$1" | tr -d '\n' | grep -Eq "$IP_REGEX"
}

#配置VPN服务器IP地址
select_ip() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入VPN服务端IP地址，默认是127.0.0.1"
		read -rp "VPN服务端IP地址: " ip
		until [ -z "$ip" ] || check_ip "$ip"; do
			echo "$ip: 非法的IP地址."
			read -rp "VPN服务端IP地址: " ip
		done
	fi
}

#配置VPN服务器端口号
select_port() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入VPN服务端端口号，默认是1194"
		read -rp "VPN服务端端口号: " port
		until [[ -z "$port" || "$port" =~ ^[0-9]+$ && "$port" -le 65535 ]]; do
			echo "$port: 非法的端口号."
			read -rp "VPN服务端端口号: " port
		done
	fi
}

#配置证书绝对路径
select_cert_path() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入证书和私钥文件的存放目录，默认是/opt/sisvpn/etc/certs"
		read -rp "证书和私钥文件目录: " cert_path

		until [[  -z "$cert_path" || -d "$cert_path" ]]; do
			echo "$cert_path: 存放证书和私钥文件的目录不存在."
			read -rp "证书和私钥文件目录: " cert_path
		done
		[[ -z "$cert_path" ]] && cert_path="/opt/sisvpn/etc/certs"
	else
		cert_path="/opt/sisvpn/etc/certs"
	fi
}

#配置ca证书
select_ca_cert() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入CA证书名称，默认是ca.crt"
		read -rp "CA证书: " ca_cert

		until [[  -z "$ca_cert" || -f "$cert_path/$ca_cert" ]]; do
			echo "$cert_path/$ca_cert: CA证书文件不存在."
			read -rp "CA证书: " ca_cert
		done
	fi
}

#配置客户端签名证书
select_cli_sign_cert() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入客户端签名证书文件名称，默认是clt_sign.crt"
		read -rp "客户端签名证书: " clt_sign_cert

		until [[  -z "$clt_sign_cert" || -f "$cert_path/$clt_sign_cert" ]]; do
			echo "$cert_path/$clt_sign_cert: 客户端签名证书文件不存在."
			read -rp "客户端签名证书: " clt_sign_cert
		done
	fi
}

#配置客户端加密证书
select_cli_enc_cert() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入客户端加密证书文件名称，默认是clt_enc.crt"
		read -rp "客户端加密证书: " clt_enc_cert

		until [[  -z "$clt_enc_cert" || -f "$cert_path/$clt_enc_cert" ]]; do
			echo "$cert_path/$clt_enc_cert: 客户端加密证书文件不存在."
			read -rp "客户端加密证书: " clt_enc_cert
		done
	fi
}

#配置客户端签名私钥
select_cli_sign_key() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入客户端签名私钥文件名称，默认是clt_sign.key"
		read -rp "客户端签名私钥: " clt_sign_key

		until [[  -z "$clt_sign_key" || -f "$cert_path/$clt_sign_key" ]]; do
			echo "$cert_path/$clt_sign_key: 客户端签名私钥文件不存在."
			read -rp "客户端签名私钥: " clt_sign_key
		done
	fi
}

#配置客户端加密私钥
select_cli_enc_key() {
	if [ "$config" = 1 ]; then
		echo
		echo "请输入客户端加密私钥文件名称，默认是clt_enc.key"
		read -rp "客户端加密私钥: " clt_enc_key

		until [[  -z "$clt_enc_key" || -f "$cert_path/$clt_enc_key" ]]; do
			echo "$cert_path/$clt_enc_key: 客户端加密私钥文件不存在."
			read -rp "客户端加密私钥: " clt_enc_key
		done
	fi
}

#配置隧道类型
select_tun_type() {
	if [ "$config" = 1 ]; then
		echo
		echo "请选择VPN使用的隧道类型?"
		echo "   1) TUN (默认)"
		echo "   2) TAP"
		read -rp "隧道类型 [1]: " tun_type
		until [[ -z "$tun_type" || "$tun_type" =~ ^[12]$ ]]; do
			echo "$tun_type: 非法选择."
			read -rp "隧道类型 [1]: " tun_type
		done
		case "$tun_type" in
			1|"")
			tun_type="tun"
			;;
			2)
			tun_type="tap"
			;;
		esac
	fi
}

#配置加密套件
select_cipher_suite() {
	if [ "$config" = 1 ]; then
		echo
		echo "请选择VPN使用的加密套件?"
		echo "   1) ECC-SM4-SM3 (默认)"
		echo "   2) ECDHE-SM4-SM3"
		read -rp "加密套件 [1]: " cipher_suite
		until [[ -z "$cipher_suite" || "$cipher_suite" =~ ^[12]$ ]]; do
			echo "$cipher_suite: 非法选择."
			read -rp "加密套件 [1]: " cipher_suite
		done
		case "$cipher_suite" in
			1|"")
			cipher_suite="ECC-SM4-SM3"
			;;
			2)
			cipher_suite="ECDHE-SM4-SM3"
			;;
		esac
	fi
}

#配置usbkey口令
select_usbkey_pin() {
	echo
	echo "请输入USBKEY口令"
	read -rp "口令: " pin
	until [ ! -z "$pin" ]; do
		echo "$pin: 口令不能为空."
		read -rp "口令: " pin
	done
}

#修改usbkey口令
mod_usbkey_pin() {
	if [ "$modpin" = 1 ]; then
		echo
		echo "请输入USBKEY新口令"
		read -rp "口令: " new_pin
		until [ ! -z "$new_pin" ]; do
			echo "$new_pin: 口令不能为空."
			read -rp "口令: " new_pin
		done
	fi
}


#读STUNNEL_CONF文件
read_stunnel_conf(){
	if [ -f $STUNNEL_CONF ]; then
		client=$(grep '^client\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		debug=$(grep '^debug\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		foreground=$(grep '^foreground\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		securityLevel=$(grep '^securityLevel\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		ciphers=$(grep '^ciphers\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		CAfile=$(grep '^CAfile\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		cert=$(grep '^cert\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		key=$(grep '^key\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		enc_cert=$(grep '^enc_cert\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		enc_key=$(grep '^enc_key\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		accept=$(grep '^accept\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		connect=$(grep '^connect\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
		output=$(grep '^output\s*=' "$STUNNEL_CONF" |  awk -F '=' '{print $2}')
	else
		client="yes"
		debug="err"
		foreground="yes"
		securityLevel=0
		ciphers="ECC-SM4-SM3"
		CAfile=""
		cert=""
		key=""
		enc_cert=""
		enc_key=""
		accept=1196
		connect="192.168.8.131:1195"
		output=""
	fi
}

#写STUNNEL_CONF文件
write_stunnel_conf(){
	[[ -n "$ip" &&  -n "$port" ]] && connect="$ip:$port"
	[[ -n "$cert_path" &&  -n "$ca_cert" ]] && CAfile="$cert_path/$ca_cert"
	[[ -n "$cert_path" &&  -n "$clt_sign_cert" ]] && cert="$cert_path/$clt_sign_cert"
	[[ -n "$cert_path" &&  -n "$clt_enc_cert" ]] && enc_cert="$cert_path/$clt_enc_cert"
	[[ -n "$cert_path" &&  -n "$clt_sign_key" ]] && key="$cert_path/$clt_sign_key"
	[[ -n "$cert_path" &&  -n "$clt_enc_key" ]] && enc_key="$cert_path/$clt_enc_key"
	[[ -n "$cipher_suite" ]] && ciphers="$cipher_suite"

	echo "client=$client
debug=$debug
output=$output
foreground=$foreground
securityLevel=$securityLevel
ciphers=$ciphers
CAfile=$CAfile
cert=$cert
key=$key
enc_cert=$enc_cert
enc_key=$enc_key
[sslvpn]
accept=$accept
connect=$connect" > "$STUNNEL_CONF"
}

#读OVPN_CONF文件
read_ovpn_conf(){
	if [ -f $OVPN_CONF ]; then
		vclient=$(grep '^client\s*' "$OVPN_CONF" |  awk '{print $1}')
		vdev=$(grep '^dev' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vproto=$(grep '^proto' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vip=$(grep '^remote' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vport=$(grep '^remote' "$OVPN_CONF" |  awk -F ' ' '{print $3}')
		vca=$(grep '^ca' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vcert=$(grep '^cert' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vkey=$(grep '^key' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vcomplzo=$(grep '^comp-lzo' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vverb=$(grep '^verb' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vkeepalive=$(grep '^keepalive' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vkeepalive1=$(grep '^keepalive' "$OVPN_CONF" |  awk -F ' ' '{print $3}')
		vtunmtu=$(grep '^tun-mtu' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
		vtopology=$(grep '^topology' "$OVPN_CONF" |  awk -F ' ' '{print $2}')
	else
		vclient=""
		vdev="tun"
		vproto="tcp"
		vip=""
		vport=1196
		vca="ovpnCA.crt"
		vcert="ovpnClient.crt"
		vkey="ovpnClient.key"
		vcomplzo="no"
		vverb=3
		vkeepalive=10
		vkeepalive1=120
		vtunmtu=1500
		vtopology="subnet"
	fi
}

#写OVPN_CONF文件
write_ovpn_conf(){
	[[ -n "$tun_type" ]] && vdev="$tun_type"

	echo "client
dev $vdev
proto $vproto
remote $vip $accept
ca $vca
cert $vcert
key $vkey
comp-lzo $vcomplzo
verb $vverb
keepalive $vkeepalive $vkeepalive1
tun-mtu $vtunmtu
topology $vtopology" > "$OVPN_CONF"
}

#1、参数分析
parse_args "$@"

#2、关闭VPN服务
if [ "$stop" = 1 ]; then
	${curr_path}/bin/ovpn_cli --stop
	exit 1
fi

if [ "$config" = 1 ]; then
	#3、读STUNNEL_CONF文件
	read_stunnel_conf
	
	#4、读OVPN_CONF文件
	read_ovpn_conf
	
	#5、交互配置参数
	select_ip
	select_port
	select_tun_type
	select_cipher_suite
	select_cert_path
	select_ca_cert
	select_cli_sign_cert
	select_cli_enc_cert
	select_cli_sign_key
	select_cli_enc_key
	
	#6、写OVPN_CONF文件
	write_ovpn_conf
	
	#7、写STUNNEL_CONF文件
	write_stunnel_conf
fi

#8、输入认证口令
select_usbkey_pin

#9、修改usbkey口令
mod_usbkey_pin

#10、修改usbkey口令
if [ "$modpin" = 1 ]; then
	mod_pin_param="--mod-user-pin ${new_pin}"
else
	mod_pin_param=""
fi

#11、启动vpn-cli客户端(验证口令、修改口令、启动stunnel和opnvpn服务)
${curr_path}/bin/ovpn_cli --install-path ${curr_path} --verify-user-pin ${pin}  ${mod_pin_param}

